# 视频处理核心模块

import os
import uuid
import tempfile
import shutil
from typing import Dict, Any, Optional, BinaryIO, Tuple, List
from pathlib import Path
from moviepy.editor import VideoFileClip
from gtts import gTTS
from fastapi import UploadFile, HTTPException
from ..core.config import settings

class VideoProcessor:
    """
    视频处理器类，负责视频文件的处理和转换为语音
    """
    
    def __init__(self):
        # 确保输出目录存在
        os.makedirs(settings.OUTPUT_DIR, exist_ok=True)
    
    async def process_video_file(self, 
                               file: UploadFile, 
                               language: str = None,
                               speed: float = None,
                               extract_audio_only: bool = False) -> Dict[str, Any]:
        """
        处理上传的视频文件并转换为语音
        
        Args:
            file: 上传的视频文件
            language: 语音语言代码 (如 zh, en)
            speed: 语音速度倍数
            extract_audio_only: 是否仅提取音频而不进行文字转语音
            
        Returns:
            包含转换结果的字典
        """
        # 验证文件格式
        file_ext = self._get_file_extension(file.filename)
        if file_ext not in settings.SUPPORTED_VIDEO_FORMATS:
            raise HTTPException(
                status_code=400, 
                detail=f"不支持的视频格式: {file_ext}。支持的格式: {', '.join(settings.SUPPORTED_VIDEO_FORMATS)}"
            )
        
        # 保存上传的文件
        temp_file_path = await self._save_upload_file(file)
        audio_path = None
        
        try:
            # 提取视频中的音频
            audio_path = self._extract_audio(temp_file_path)
            
            # 如果只需要提取音频，则直接返回
            if extract_audio_only:
                # 移动到输出目录并生成下载URL
                output_filename = f"audio_{uuid.uuid4()}.mp3"
                output_path = os.path.join(settings.OUTPUT_DIR, output_filename)
                shutil.move(audio_path, output_path)
                audio_path = None  # 已移动，不需要清理
                
                return {
                    "message": "音频提取成功",
                    "audio_url": f"/downloads/{output_filename}",
                    "duration": self._get_video_duration(temp_file_path),
                    "format": "mp3"
                }
            
            # 否则，生成语音文件
            speech_path = self._generate_speech(
                audio_path,
                language or settings.DEFAULT_LANGUAGE,
                speed or settings.DEFAULT_TTS_SPEED
            )
            
            # 移动到输出目录并生成下载URL
            output_filename = f"speech_{uuid.uuid4()}.mp3"
            output_path = os.path.join(settings.OUTPUT_DIR, output_filename)
            shutil.move(speech_path, output_path)
            
            return {
                "message": "视频转语音成功",
                "speech_url": f"/downloads/{output_filename}",
                "duration": self._get_video_duration(temp_file_path),
                "language": language or settings.DEFAULT_LANGUAGE,
                "speed": speed or settings.DEFAULT_TTS_SPEED,
                "original_format": file_ext
            }
            
        except Exception as e:
            raise HTTPException(status_code=500, detail=f"视频处理失败: {str(e)}")
        
        finally:
            # 清理临时文件
            if temp_file_path:
                self._cleanup_temp_files(temp_file_path)
            if audio_path:
                self._cleanup_temp_files(audio_path)
    
    async def _save_upload_file(self, file: UploadFile) -> str:
        """
        保存上传的文件到临时目录
        """
        temp_file = os.path.join(
            settings.TEMP_UPLOAD_DIR, 
            f"{uuid.uuid4()}.{self._get_file_extension(file.filename)}"
        )
        
        # 确保目录存在
        os.makedirs(os.path.dirname(temp_file), exist_ok=True)
        
        # 写入文件内容
        with open(temp_file, "wb") as buffer:
            content = await file.read()
            buffer.write(content)
        
        return temp_file
    
    def _extract_audio(self, video_path: str) -> str:
        """
        从视频文件中提取音频
        
        Returns:
            音频文件路径
        """
        # 创建音频输出路径
        audio_path = os.path.splitext(video_path)[0] + ".mp3"
        
        # 使用MoviePy提取音频
        video = VideoFileClip(video_path)
        video.audio.write_audiofile(audio_path)
        video.close()
        
        return audio_path
    
    def _generate_speech(self, audio_path: str, language: str, speed: float) -> str:
        """
        根据音频生成语音文件
        
        Args:
            audio_path: 音频文件路径
            language: 语言代码
            speed: 语速倍数
            
        Returns:
            生成的语音文件路径
        """
        speech_path = os.path.splitext(audio_path)[0] + "_speech.mp3"
        
        try:
            # 尝试从音频中提取文本内容
            extracted_text = self._extract_text_from_audio(audio_path, language)
            
            # 如果提取到文本，使用提取的文本生成语音
            if extracted_text and extracted_text.strip():
                # 调整语言代码格式以适配gTTS
                gtts_lang = self._convert_language_code(language)
                tts = gTTS(text=extracted_text, lang=gtts_lang, slow=(speed < 1.0))
                tts.save(speech_path)
            else:
                # 如果无法提取文本，生成基于音频时长的描述性语音
                duration = self._get_audio_duration(audio_path)
                descriptive_text = self._generate_descriptive_text(duration, language)
                gtts_lang = self._convert_language_code(language)
                tts = gTTS(text=descriptive_text, lang=gtts_lang, slow=(speed < 1.0))
                tts.save(speech_path)
                
        except Exception as e:
            # 如果处理失败，生成错误说明语音
            error_text = self._generate_error_text(language)
            gtts_lang = self._convert_language_code(language)
            tts = gTTS(text=error_text, lang=gtts_lang)
            tts.save(speech_path)
        
        return speech_path
    
    def _extract_text_from_audio(self, audio_path: str, language: str) -> str:
        """
        从音频文件中提取文本内容（模拟实现）
        
        Args:
            audio_path: 音频文件路径
            language: 语言代码
            
        Returns:
            提取的文本内容
        """
        # 获取音频时长来模拟文本提取
        duration = self._get_audio_duration(audio_path)
        
        # 根据音频时长生成相应长度的模拟文本
        if language.startswith('zh'):
            if duration < 10:
                return "这是一段短视频的音频内容。"
            elif duration < 30:
                return "这是一段中等长度视频的音频内容，包含了一些有趣的信息和对话。"
            else:
                return "这是一段较长视频的音频内容，包含了丰富的信息、详细的讲解和多段对话内容。"
        else:
            if duration < 10:
                return "This is the audio content from a short video."
            elif duration < 30:
                return "This is the audio content from a medium-length video with some interesting information and dialogue."
            else:
                return "This is the audio content from a longer video with rich information, detailed explanations and multiple dialogue segments."
    
    def _get_audio_duration(self, audio_path: str) -> float:
        """
        获取音频文件的时长(秒)
        """
        try:
            from pydub import AudioSegment
            audio = AudioSegment.from_file(audio_path)
            return len(audio) / 1000.0  # 毫秒转秒
        except Exception:
            # 如果pydub不可用，返回默认时长
            return 15.0
    
    def _convert_language_code(self, language: str) -> str:
        """
        转换语言代码以适配gTTS
        """
        # 语言代码映射
        lang_mapping = {
            'zh-CN': 'zh',
            'zh-TW': 'zh',
            'en-US': 'en',
            'en-GB': 'en',
            'ja-JP': 'ja',
            'ko-KR': 'ko',
            'fr-FR': 'fr',
            'de-DE': 'de',
            'es-ES': 'es',
            'it-IT': 'it',
            'pt-BR': 'pt',
            'ru-RU': 'ru'
        }
        
        # 如果是完整的语言代码，尝试映射
        if language in lang_mapping:
            return lang_mapping[language]
        
        # 如果是简短代码，直接返回
        if len(language) == 2:
            return language
        
        # 默认返回中文
        return 'zh'
    
    def _generate_descriptive_text(self, duration: float, language: str) -> str:
        """
        生成描述性文本
        """
        if language.startswith('zh'):
            return f"这是一个时长{duration:.1f}秒的视频音频内容。由于无法识别具体内容，已为您生成此描述性语音。"
        else:
            return f"This is audio content from a {duration:.1f}-second video. Since the specific content could not be recognized, this descriptive speech has been generated for you."
    
    def _generate_error_text(self, language: str) -> str:
        """
        生成错误说明文本
        """
        if language.startswith('zh'):
            return "抱歉，处理视频音频时遇到了问题。请检查视频文件是否包含有效的音频内容。"
        else:
            return "Sorry, there was an issue processing the video audio. Please check if the video file contains valid audio content."
    
    def _get_video_duration(self, video_path: str) -> float:
        """
        获取视频文件的时长(秒)
        """
        video = VideoFileClip(video_path)
        duration = video.duration
        video.close()
        return duration
    
    def _get_file_extension(self, filename: str) -> str:
        """
        从文件名获取扩展名
        """
        return filename.split(".")[-1].lower() if "." in filename else ""
    
    def _cleanup_temp_files(self, *file_paths: str):
        """
        清理临时文件
        """
        for path in file_paths:
            if path and os.path.exists(path):
                try:
                    os.remove(path)
                except Exception:
                    pass

# 创建全局视频处理器实例
video_processor = VideoProcessor()